// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief Implementation of File Utility functions for 1-D Association Scans 
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "assoc_utils.h"
#include "copyfile.h"
#include "suffixes.h"
#include "utils.h"

int count_file_write_and_copy(struct selected_options *ops, char *suffix, int rank, int numprocs, int nperm_done, int size, int *R, int *maxR) {
	FILE *out = NULL;
	BOOL jobDone = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];

	if (ops == NULL || suffix == NULL || rank < 0 || numprocs <= 0 || size <= 0 || R == NULL || maxR == NULL) return 0;
	else if (strlen(ops->szRunId) == 0 || strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(suffix) == 0) return 0;

	set_datafile_path(localFilepath, ops->ldir, ops->szRunId, rank, suffix);
	set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, rank, suffix);

	out = fopen(localFilepath, "w");
	if (out != NULL) {
		int i; 

		// Header info, numprocs & num of permutations done on the rank.
		fprintf(out, "%i\n", numprocs);
		fprintf(out, "%i\n", nperm_done);
		for (i = 0; i < size; i++) fprintf(out, "%i,%i\n", R[i], maxR[i]);
		fclose(out);
		if(copyAndDeleteFile(localFilepath, remoteFilepath)) jobDone = TRUE;
	}

	if (jobDone) return 1;
	else return 0;
}

int count_file_copy_and_parse(struct selected_options *ops, char *suffix, int numprocs, int size, int *nperm_done, int *R, int *maxR, BOOL *hasCopiedAll, BOOL *file_copy_failures) {
	int i, j;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH], line[MAX_LINE_LENGTH];

	if (ops == NULL || suffix == NULL || numprocs <= 0 || size <= 0 || R == NULL || maxR == NULL || hasCopiedAll == NULL || file_copy_failures == NULL || nperm_done == NULL) return 0;
	else if (strlen(ops->szRunId) == 0 || strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(suffix) == 0) return 0;

	*hasCopiedAll = TRUE;
	*nperm_done = 0;


	for (i = 0; i < numprocs; i++) {
		set_datafile_path(localFilepath, ops->ldir, ops->szRunId, i, suffix);
		set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, i, suffix);
		if(copyFile(remoteFilepath, localFilepath)) {
			FILE *in = fopen(localFilepath, "r");
			if (in != NULL) {
				fgets(line, MAX_LINE_LENGTH, in); // Skip the header line.
				fgets(line, MAX_LINE_LENGTH, in);
				*nperm_done = *nperm_done + atoi(line);
				j = 0;
				while(fgets(line, MAX_LINE_LENGTH, in) != NULL && j < size) {
					if (strlen(line) > 0) {
						char token[80];

						get_token(line, token, 0, ',');
						R[j] += atoi(token);
						get_token(line, token, 1, ',');
						maxR[j] += atoi(token);
						j++;
					}
				}
				fclose(in);
				deleteFile(localFilepath);
			}
		} else {
			*hasCopiedAll = FALSE;
			file_copy_failures[i] = TRUE;
		}
	}

	if (*hasCopiedAll) return 1;
	else return 0;
	
}

int write_failed_rank_log(struct selected_options *ops, int numprocs, BOOL *failures) {
	FILE *out = NULL;
	BOOL jobDone = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];

	if (ops == NULL || numprocs <= 0 || failures == NULL) return 0;
	else if (strlen(ops->szRunId) == 0 || strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0) return 0;

	sprintf(localFilepath, "%s%s%s", ops->ldir, ops->szRunId, SUFFIX_MERGE_LOG);
	sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_MERGE_LOG);	
	out = fopen(localFilepath, "w");
	if (out != NULL) {
		int i;
		time_t now = time(NULL);

		fprintf(out, "Dated=%s", ctime(&now));
		fprintf(out, "Numprocs=%i\n", numprocs);
		fprintf(out, "Failed Ranks=");
		for (i = 0; i < numprocs; i++) {
			if (failures[i] == TRUE) fprintf(out, "%i ", i);
		}
		fprintf(out, "\n");
		fclose(out);
		if(copyAndDeleteFile(localFilepath, remoteFilepath)) jobDone = TRUE;
	}
	
	if (jobDone) return 1;
	else return 0;
}

int assoc_cleanup_temp_files(struct selected_options *ops, char *suffix, int numprocs) {
	int i;
	char remoteFilepath[FILE_PATH_LENGTH];
#ifndef PCMH
	int nSuffixes_to_del = 7;
	char *suffixes_to_del[] = { SUFFIX_BMAP_FILE, SUFFIX_PERM_FILE, SUFFIX_PERSON_TO_DEL, SUFFIX_SPED_FILE, SUFFIX_RSEED_FILE, SUFFIX_SAMPLE_FILE, SUFFIX_PADJ_FILE};
#else
	int nSuffixes_to_del = 8;
	char *suffixes_to_del[] = { SUFFIX_BMAP_FILE, SUFFIX_PERM_FILE, SUFFIX_PERSON_TO_DEL, SUFFIX_SPED_FILE, SUFFIX_RSEED_FILE, SUFFIX_SAMPLE_FILE, SUFFIX_PADJ_FILE, SUFFIX_SOL_FILE};
#endif

	if (ops == NULL || suffix == NULL || numprocs <= 0) return 0;
	else if (strlen(ops->szRunId) == 0 || strlen(suffix) == 0 || strlen(ops->rdir) == 0) return 0;

	// Delete data from each rank.
	for (i = 0; i < numprocs; i++) {
		set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, i, suffix);
		deleteFile(remoteFilepath);
	}

	for (i = 0; i < nSuffixes_to_del; i++)  {
		sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, suffixes_to_del[i]);
		deleteFile(remoteFilepath);
	}
	
	return 1;
}

int _count_file_write_and_copy(struct selected_options *ops, char *suffix, int rank, int numprocs, int nperm_done, int size, int *R, int *maxR) {
	FILE *out = NULL;
	BOOL jobDone = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];

	if (ops == NULL || suffix == NULL || rank < 0 || numprocs <= 0 || size <= 0 || R == NULL || maxR == NULL) return 0;
	else if (strlen(ops->szRunId) == 0 || strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(suffix) == 0) return 0;

	set_datafile_path(localFilepath, ops->ldir, ops->szRunId, rank, suffix);
	set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, rank, suffix);

	out = fopen(localFilepath, "wb");
	if (out != NULL) {
		int i; 

		// Header info, numprocs & num of permutations done on the rank.
		if(fwrite(&numprocs, sizeof(numprocs), 1, out)) {
			if(fwrite(&nperm_done, sizeof(nperm_done), 1, out)) {
				int *buffer = calloc(size, sizeof(int) * 2), *pBuffer = NULL;
				if (buffer != NULL) {
					size_t expected_amount = size * sizeof(int) * 2;
					for (i = 0, pBuffer = buffer; i < size; i++, pBuffer += 2) {
						pBuffer[0] = R[i];
						pBuffer[1] = maxR[i];
					}
					if(fwrite(buffer, expected_amount, 1, out) == 1) jobDone = TRUE;
					free(buffer);
				}
			}
		}
		fclose(out);

		if(jobDone) jobDone = copyAndDeleteFile(localFilepath, remoteFilepath) ? TRUE : FALSE;
		else deleteFile(localFilepath);
	}

	if (jobDone) return 1;
	else return 0;
}

BOOL* _count_file_parse(struct selected_options *ops, char *suffix, int size, int *nperm_done, int *R, int *maxR, BOOL *hasCopiedAll, int *numprocs) {
	FILE *in = NULL;
	int i, j;
	char remoteFilepath[FILE_PATH_LENGTH];
	int _numprocs = 0, _nperm_done = 0;
	BOOL *file_copy_failures = NULL;
	int *buffer = NULL, *pBuffer = NULL;
	size_t expected_amount = size * sizeof(int) * 2;

	if (ops == NULL || suffix == NULL || size <= 0 || R == NULL || maxR == NULL || hasCopiedAll == NULL || nperm_done == NULL) return file_copy_failures;
	else if (strlen(ops->szRunId) == 0 || strlen(ops->ldir) == 0 || strlen(suffix) == 0) return file_copy_failures;

	*hasCopiedAll = TRUE;
	*nperm_done = 0;
	*numprocs = 0;
	
	// Try to read the number of cores
	for (i = 0; i < AVAILABLE_CORES; i++) {
		set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, i, suffix);
		in = fopen(remoteFilepath, "rb");
		if (in != NULL) {
			if(fread(numprocs, sizeof(int), 1, in) == 1)  {
				if (*numprocs > 0) {
					fclose(in);
					break;
				}
			}
		}
		if (in != NULL) fclose(in);
	}
	if (*numprocs <= 0) { 
		hasCopiedAll = FALSE;
		return NULL;
	}
	*numprocs = 4;
	buffer = (int*) malloc(expected_amount);
	if (buffer == NULL) {
		hasCopiedAll = FALSE;
		return NULL;
	}
	file_copy_failures = create_bool_array(*numprocs, FALSE); 
	*hasCopiedAll = TRUE;
	for (i = 0; i < *numprocs; i++) {
		set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, i, suffix);
		in = fopen(remoteFilepath, "rb");
		if (in != NULL) {
			BOOL readCounts = FALSE;
			if(fread(&_numprocs, sizeof(_numprocs), 1, in) == 1)  {
				if (*numprocs == _numprocs) {
					if(fread(&_nperm_done, sizeof(_nperm_done), 1, in) == 1) {
						if (fread(buffer, expected_amount, 1, in) == 1)  readCounts = TRUE;
					}
				}
			}
			if (readCounts) {
				*nperm_done += _nperm_done;

				// 2 columns of numbers, the R and maxR counts.
				for (j = 0, pBuffer = buffer; j < size; j++, pBuffer += 2) {
					R[j] += pBuffer[0];
					maxR[j] += pBuffer[1];
				}
			}
		} else {
			hasCopiedAll = FALSE;
			file_copy_failures[i] = TRUE;
		}
		if (in != NULL) fclose(in);
	}
	if (buffer != NULL) free(buffer);
	
	return file_copy_failures;
}
